﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Security;
using System.Data.Common;
using System.Data.SqlClient;
using System.Configuration;
using System.Text;
using System.Data;
using System.Text.RegularExpressions;
using SIMCFachadaNegocio;
using SIMCObjetoNegocio;

/// <summary>
/// Summary description for ADAMMembershipProvider
/// </summary>
public class SimcMembershipProvider : SqlMembershipProvider
{
    private MembershipUsuario _User;

    private FachadaSeguridad fachadaSeguridad;

    public MembershipUsuario Usuario
    {
        get { return _User; }
        set { _User = value; }
    }
    string ConexAutenticacionConnectionString = ConfigurationManager.ConnectionStrings["ConexAutenticacion"].ToString();

    public SimcMembershipProvider()
    {
        fachadaSeguridad = new FachadaSeguridad();
    }

    public override bool ValidateUser(string strName, string strPassword)
    {

        try
        {
            _User = ((MembershipUsuario)this.GetUser(strName, true));

            if (_User != null)
            {
                return base.ValidateUser(strName, strPassword); 
            }

            return false;
        }
        catch (Exception ex)
        {
            throw ex;
        }

       
    }

    private bool ComprobarLoginEnSQLServer(string strName, string strPassword)
    {
        bool esValido = true;
        string connectionString = ConfigurationManager.ConnectionStrings["ConexUserSIMC"] + "User ID=" + strName + ";Password=" + strPassword;

        DbProviderFactory factory;
        string dataProvider = "System.Data.SqlClient";
        factory = DbProviderFactories.GetFactory(dataProvider);

        using (DbConnection connection = factory.CreateConnection())
        {

            connection.ConnectionString = connectionString;
            try
            {
                connection.Open();

            }
            catch (Exception ex)
            {
                esValido = false;
            }
            finally
            {
                connection.Close();
            }
        }

        return esValido;
    }

    public override string ApplicationName
    {
        get
        {
            return base.ApplicationName;
        }
        set
        {
            value = base.ApplicationName;
        }
    }

    public override bool ChangePassword(string username, string oldPassword, string newPassword)
    {
        try
        {
            return base.ChangePassword(username, oldPassword, newPassword);
        }
        catch (Exception ex)
        {
            throw;
        }
    }

    public override bool ChangePasswordQuestionAndAnswer(string username, string password, string newPasswordQuestion, string newPasswordAnswer)
    {
        return base.ChangePasswordQuestionAndAnswer(username, password, newPasswordQuestion, newPasswordAnswer);
    }

    public override MembershipUser CreateUser(string username, string password, string email, string passwordQuestion, string passwordAnswer, bool isApproved, object providerUserKey, out MembershipCreateStatus status)
    {
        int userId = fachadaSeguridad.ValidarAcceso(username, "");
        if (userId <= 0)//Si el nombre no esta siendo usado por ningun ususario interno se puede crear el ususrio externo.
        {
            MembershipUser memUser = base.CreateUser(username, password, email, passwordQuestion, passwordAnswer, isApproved, providerUserKey, out status);
            return MapMembership(memUser);
        }
        else
        {
            status = MembershipCreateStatus.DuplicateUserName;
            return null;
        }
    }
    public MembershipUser CreateUsuario(string username,
                                        string password,
                                        string email,
                                        string passwordQuestion,
                                        string passwordAnswer,
                                        bool isApproved,
                                        object providerUserKey,
                                        out MembershipCreateStatus status,
                                        string telefono,
                                        string Nombre,
                                        string Apellido)
    {
        int userId = fachadaSeguridad.ValidarAcceso(username, "");
        if (userId <= 0)//Si el nombre no esta siendo usado por ningun ususario interno se puede crear el ususrio externo.
        {
            MembershipUser user = base.CreateUser(username, password, email, passwordQuestion, passwordAnswer, isApproved, providerUserKey, out status);
            if (user != null)
            {
                MembershipUsuario memUser = MapMembership(user);
                memUser.Telefono = telefono;
                memUser.TempPasswordDate = DateTime.Now;
                memUser.Nombre = Nombre;
                memUser.Apellido = Apellido;
                this.UpdateUsuario(memUser);

                return memUser;
            }
            else
                return null;
        }
        else
        {
            status = MembershipCreateStatus.DuplicateUserName;
            return null;
        }
    }

    public override bool DeleteUser(string username, bool deleteAllRelatedData)
    {
        return base.DeleteUser(username, deleteAllRelatedData);
    }

    public override bool EnablePasswordReset
    {
        get { return base.EnablePasswordReset; }
    }

    public override bool EnablePasswordRetrieval
    {
        get { return base.EnablePasswordRetrieval; }
    }

    public override MembershipUserCollection FindUsersByEmail(string emailToMatch, int pageIndex, int pageSize, out int totalRecords)
    {
        return base.FindUsersByEmail(emailToMatch, pageIndex, pageSize, out  totalRecords);
    }

    public override MembershipUserCollection FindUsersByName(string usernameToMatch, int pageIndex, int pageSize, out int totalRecords)
    {
        return base.FindUsersByName(usernameToMatch, pageIndex, pageSize, out  totalRecords);
    }

    public override MembershipUserCollection GetAllUsers(int pageIndex, int pageSize, out int totalRecords)
    {
        return base.GetAllUsers(pageIndex, pageSize, out  totalRecords);
    }

    public override int GetNumberOfUsersOnline()
    {
        return base.GetNumberOfUsersOnline();
    }

    public override string GetPassword(string username, string answer)
    {
        return base.GetPassword(username, answer);
    }

    public override MembershipUser GetUser(string username, bool userIsOnline)
    {
        int userId = 0;
        MembershipUsuario user = new MembershipUsuario();
        try
        {
            userId = fachadaSeguridad.ValidarAcceso(username, "");
            if (userId > 0)//ES USUARIO INTERNO
            {
                Usuario userObject = fachadaSeguridad.BuscarUsuario(userId);
                user = new MembershipUsuario(base.Name, userObject.Login, userObject, userObject.email, "", "", true, false, DateTime.MinValue, userObject.UltimoLogin, userObject.UltimoLogout, DateTime.MinValue, DateTime.MinValue);
                user.TipoUsuario = TipoUsuario.Interno;
                user.TempPasswordDate = DateTime.MinValue;
                user.NombreCompleto = userObject.NombreCorto;
                user.UserId = userObject.Id;
                user.rol = userObject.Rol;
                return user;
            }
            else
            {
                return null;
            }
        }
        catch (SIMCFachadaNegocio.Excepciones.InactivoLoginException ex)
        {
            throw ex;
        }
        catch (SIMCFachadaNegocio.Excepciones.FallaLoginException ex)
        {
            //PUEDE SER USUARIO EXTERNO
            MembershipUser memUser = base.GetUser(username, userIsOnline);

            if (memUser != null)
            {
                user = GetUsuarioCompleto(memUser);
                user.TipoUsuario = TipoUsuario.Externo;
                user.rol = new Rol { Id = "UEX", Descripcion = "Usuario externo" };
                return user;
            }
            else
            {
                return null;
            }
        }
        catch (Exception ex)
        {
            throw ex;
        }

    }

    private MembershipUsuario GetUsuarioCompleto(MembershipUser memUser)
    {
        MembershipUsuario user = MapMembership(memUser);

        string connectionString = ConfigurationManager.ConnectionStrings["ConexAutenticacion"].ToString();

        Helper.Db db = new Helper.Db(connectionString);

        StringBuilder sql = new StringBuilder();

        sql.Append("DECLARE @UserId uniqueidentifier ");
        sql.Append("DECLARE @ApplicationId uniqueidentifier ");
        sql.Append("SELECT  @UserId = NULL ");
        sql.Append("SELECT  @UserId = u.UserId, @ApplicationId = a.ApplicationId ");
        sql.Append("FROM    dbo.aspnet_Users u, dbo.aspnet_Applications a, dbo.aspnet_Membership m ");
        sql.Append("WHERE   LoweredUserName = LOWER('" + user.UserName + "') AND ");
        sql.Append("u.ApplicationId = a.ApplicationId  AND ");
        sql.Append("LOWER('" + this.ApplicationName + "') = a.LoweredApplicationName AND ");
        sql.Append("u.UserId = m.UserId ");

        sql.Append(" select Telefono, TempPasswordDate, Name, LastName from  [aspnet_Users] ");
        sql.Append(" where UserId = @UserId and ApplicationId = @ApplicationId");

        DataRow row = db.GetDataRow(sql.ToString());

        user.Telefono = row["Telefono"].ToString();
        user.TempPasswordDate = Helper.DBHelper.GetDateTime(row, "TempPasswordDate");
        user.Nombre = row["Name"].ToString();
        user.Apellido = row["LastName"].ToString();

        return user;
    }

    public override MembershipUser GetUser(object providerUserKey, bool userIsOnline)
    {
        throw new NotImplementedException();
    }

    public override string GetUserNameByEmail(string email)
    {
        throw new NotImplementedException();
    }

    public override int MaxInvalidPasswordAttempts
    {
        get { return base.MaxInvalidPasswordAttempts; }
    }

    public override int MinRequiredNonAlphanumericCharacters
    {
        get { return base.MinRequiredNonAlphanumericCharacters; }
    }

    public override int MinRequiredPasswordLength
    {
        get { return base.MinRequiredPasswordLength; }
    }

    public override int PasswordAttemptWindow
    {
        get { return base.PasswordAttemptWindow; }
    }

    public override MembershipPasswordFormat PasswordFormat
    {
        get { return base.PasswordFormat; }
    }

    public override string PasswordStrengthRegularExpression
    {
        get { return base.PasswordStrengthRegularExpression; }
    }

    public override bool RequiresQuestionAndAnswer
    {
        get { return base.RequiresQuestionAndAnswer; }
    }

    public override bool RequiresUniqueEmail
    {
        get { return base.RequiresUniqueEmail; }
    }

    public override string ResetPassword(string username, string answer)
    {
        try
        {
            string TempPassword = base.ResetPassword(username, answer);
            MembershipUsuario user = ((MembershipUsuario)this.GetUser(username, false));

            user.TempPasswordDate = DateTime.Now;

            this.UpdateUsuario(user);

            return TempPassword;
        }
        catch (Exception ex)
        {
            throw new ArgumentException("Ha ocurrido un inconveniente: " + ex.Message);
        }
    }

    public override bool UnlockUser(string userName)
    {
        return base.UnlockUser(userName);
    }

    public override void UpdateUser(MembershipUser user)
    {
        base.UpdateUser(user);

        this.UpdateUsuario((MembershipUsuario)user);
    }

    public void BloquearUsuario(MembershipUsuario usuario)
    {
        usuario.IsApproved = false;

        this.UpdateUser(usuario);
    }

    public void DesbloquearUsuario(MembershipUsuario usuario)
    {
        usuario.IsApproved = true;

        this.UpdateUser(usuario);
    }

    private void UpdateUsuario(MembershipUsuario usuario)
    {
        string connectionString = ConfigurationManager.ConnectionStrings["ConexAutenticacion"].ToString();

        Helper.Db db = new Helper.Db(connectionString);
        StringBuilder sql = new StringBuilder();

        sql.Append("DECLARE @UserId uniqueidentifier ");
        sql.Append("DECLARE @ApplicationId uniqueidentifier ");
        sql.Append("SELECT  @UserId = NULL ");
        sql.Append("SELECT  @UserId = u.UserId, @ApplicationId = a.ApplicationId ");
        sql.Append("FROM    dbo.aspnet_Users u, dbo.aspnet_Applications a, dbo.aspnet_Membership m ");
        sql.Append("WHERE   LoweredUserName = LOWER('" + usuario.UserName + "') AND ");
        sql.Append("u.ApplicationId = a.ApplicationId  AND ");
        sql.Append("LOWER('" + this.ApplicationName + "') = a.LoweredApplicationName AND ");
        sql.Append("u.UserId = m.UserId ");

        sql.Append(" Update [aspnet_Users] set ");
        sql.Append(" [Telefono] = '" + usuario.Telefono + "'");
        sql.Append(" ,[Name] = '" + usuario.Nombre + "'");
        sql.Append(" ,[LastName] = '" + usuario.Apellido + "'");
        if (usuario.TempPasswordDate != DateTime.MinValue)
        {
            sql.Append(", [TempPasswordDate] = '" + usuario.TempPasswordDate.ToString("yyyy/MM/dd HH:mm:ss") + "'");
        }
        else
        {
            sql.Append(", [TempPasswordDate] = NULL");
        }
        sql.Append(" where UserId = @UserId and ApplicationId = @ApplicationId");

        db.Update(sql.ToString());
    }

    public MembershipUsuario MapMembership(MembershipUser param_member)
    {
        return new MembershipUsuario(param_member.ProviderName, param_member.UserName, param_member.ProviderUserKey, param_member.Email, param_member.PasswordQuestion, param_member.Comment, param_member.IsApproved, param_member.IsLockedOut, param_member.CreationDate
                , param_member.LastLoginDate, param_member.LastActivityDate, param_member.LastPasswordChangedDate, param_member.LastLockoutDate);
    }

    public void ActualizarUsuario()
    {
        _User = (MembershipUsuario)this.GetUser(_User.UserName, true);
    }

    public void ValidatePassword(string password, string username)
    {
        if (password.Length < this.MinRequiredPasswordLength)
        {
            throw new ArgumentException("La contraseña debe tener mas de " + this.MinRequiredPasswordLength + " caracteres.");
        }
        if (password.Contains(username))
        {
            throw new ArgumentException("El nombre de usuario no debe estar incluido en la contraseña.");
        }
        if (username.Contains(password))
        {
            throw new ArgumentException("La contraseña no debe estar incluida en el nombre de usuario.");
        }
        if (username.Contains(" "))
        {
            throw new ArgumentException("El nombre de usuario no debe tener espacios.");
        }
        if (password.Contains(" "))
        {
            throw new ArgumentException("La contraseña no debe tener espacios.");
        }

        int cantConjuntos = 0;
        try
        {
            cantConjuntos = Convert.ToInt32(ConfigurationManager.AppSettings["CantidadConjuntosPassword"]);
        }
        catch (Exception ex)
        {
            throw new ArgumentException("Cantidad invalida de conjuntos en webConfig");
        }

        if (!this.TieneMinusculas(password) && (cantConjuntos > 0))
        {
            throw new ArgumentException("La contraseña debe tener al menos una letra minuscula.");
        }
        if (!this.TieneMayusculas(password) && (cantConjuntos > 1))
        {
            throw new ArgumentException("La contraseña debe tener al menos una letra mayuscula.");
        }
        if (!this.TieneNumeros(password) && (cantConjuntos > 2))
        {
            throw new ArgumentException("La contraseña debe tener al menos un numero.");
        }
        if (!this.TieneCaracteresEspeciales(password) && (cantConjuntos > 3))
        {
            throw new ArgumentException("La contraseña debe tener al menos un caracter especial");
        }
    }

    private bool TieneMinusculas(string strToCheck)
    {
        Regex objAlphaNumericPattern = new Regex("[+a-z]");

        return objAlphaNumericPattern.IsMatch(strToCheck);
    }

    private bool TieneMayusculas(string strToCheck)
    {
        Regex objAlphaNumericPattern = new Regex("[+A-Z]");

        return objAlphaNumericPattern.IsMatch(strToCheck);
    }

    private bool TieneNumeros(string strToCheck)
    {
        Regex objAlphaNumericPattern = new Regex("[+0-9]");

        return objAlphaNumericPattern.IsMatch(strToCheck);
    }

    private bool TieneCaracteresEspeciales(string strToCheck)
    {
        Regex objAlphaNumericPattern = new Regex("[+#$&=*]");

        return objAlphaNumericPattern.IsMatch(strToCheck);
    }

    private bool TieneCaracteresProhibidos(string strToCheck)
    {
        Regex objAlphaNumericPattern = new Regex("[+#$&=*]");

        return objAlphaNumericPattern.IsMatch(strToCheck);
    }

    // Inicio Lili

    public List<MembershipUsuario> GetUsuarioPorLogin(string Login)
    {

        MembershipUsuario User = new MembershipUsuario();

        List<MembershipUsuario> UserList = new List<MembershipUsuario>();

        string ConnectionString = ConfigurationManager.ConnectionStrings["ConexAutenticacion"].ToString();

        Helper.Db db = new Helper.Db(ConnectionString);

        StringBuilder Sql = new StringBuilder();

        Sql.Append(" select [UserName], [Name], [LastName] from  [aspnetdb].[dbo].[aspnet_Users], [aspnetdb].[dbo].[aspnet_Applications]");
        Sql.Append(" where [LoweredApplicationName] = LOWER('" + this.ApplicationName + "') AND");
        Sql.Append(" [UserName] like '" + Login + "%'");

        DataTable dt = db.GetDataTable(Sql.ToString());

        foreach (DataRow row in dt.Rows)
        {

            MembershipUser memUser = base.GetUser(row["UserName"].ToString(), false);
            User = MapMembership(memUser);
            User.Apellido = row["LastName"].ToString();
            User.Nombre = row["Name"].ToString();
            User.TipoUsuario = TipoUsuario.Externo;
            UserList.Add(User);

        }

        BuscarUsuariosInternos(Login, string.Empty, string.Empty, UserList);

        return UserList;
    }

    public List<MembershipUsuario> GetUsuarioPorEmail(string Email)
    {
        MembershipUsuario User = new MembershipUsuario();

        List<MembershipUsuario> UserList = new List<MembershipUsuario>();

        string ConnectionString = ConfigurationManager.ConnectionStrings["ConexAutenticacion"].ToString();

        Helper.Db db = new Helper.Db(ConnectionString);

        StringBuilder Sql = new StringBuilder();

        Sql.Append(" select [UserName], [Name], [LastName] from  [aspnetdb].[dbo].[aspnet_Users] u,");
        Sql.Append(" [aspnetdb].[dbo].[aspnet_Applications] a,[aspnetdb].[dbo].[aspnet_Membership] m");
        Sql.Append(" where [LoweredApplicationName] = LOWER('" + this.ApplicationName + "') AND");
        Sql.Append(" u.[UserId] = m.[UserId] AND");
        Sql.Append(" [Email] = '" + Email + "\'");

        DataTable dt = db.GetDataTable(Sql.ToString());

        foreach (DataRow row in dt.Rows)
        {

            MembershipUser memUser = base.GetUser(row["UserName"].ToString(), false);
            User = MapMembership(memUser);
            User.Apellido = row["LastName"].ToString();
            User.Nombre = row["Name"].ToString();
            User.TipoUsuario = TipoUsuario.Externo;
            UserList.Add(User);

        }
        BuscarUsuariosInternos(string.Empty, string.Empty, Email, UserList);

        return UserList;
    }

    public List<MembershipUsuario> GetUsuariosPorNombre(string Nombre)
    {
        MembershipUsuario User = new MembershipUsuario();

        List<MembershipUsuario> UserList = new List<MembershipUsuario>();

        string ConnectionString = ConfigurationManager.ConnectionStrings["ConexAutenticacion"].ToString();

        Helper.Db db = new Helper.Db(ConnectionString);

        StringBuilder Sql = new StringBuilder();

        Sql.Append(" select [UserName], [Name], [LastName] from  [aspnetdb].[dbo].[aspnet_Users], [aspnetdb].[dbo].[aspnet_Applications]");
        Sql.Append(" where [LoweredApplicationName] = LOWER('" + this.ApplicationName + "') AND");
        Sql.Append(" [Name] like '" + Nombre + "%'");

        DataTable dt = db.GetDataTable(Sql.ToString());

        foreach (DataRow row in dt.Rows)
        {

            MembershipUser memUser = base.GetUser(row["UserName"].ToString(), false);
            User = MapMembership(memUser);
            User.Apellido = row["LastName"].ToString();
            User.Nombre = row["Name"].ToString();
            User.TipoUsuario = TipoUsuario.Externo;
            UserList.Add(User);

        }

        BuscarUsuariosInternos(string.Empty, Nombre, string.Empty, UserList);

        return UserList;
    }

    // Fin Lili

    private void BuscarUsuariosInternos(string Login, string nombre, string email, List<MembershipUsuario> UserList)
    {
        IList<Usuario> usuariosInternos = fachadaSeguridad.BuscarUsuariosConRolExterno(Login, nombre, email);

        if (usuariosInternos != null)
        {
            foreach (Usuario user in usuariosInternos)
            {
                MembershipUsuario usuario = new MembershipUsuario(base.Name, user.Login, user, user.email, "", "", true, false, DateTime.MinValue, user.UltimoLogin, user.UltimoLogout, DateTime.MinValue, DateTime.MinValue);
                usuario.TipoUsuario = TipoUsuario.Interno;
                UserList.Add(usuario);
            }
        }
    }
}